# Copyright 2010 Graphical Timeline authors (see AUTHORS file)
#
# This file is part of Graphical Timeline.
#
# Graphical Timeline is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Graphical TImeline is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Graphical Timeline.  If not, see <http://www.gnu.org/licenses/>.

from trac.core import *
from trac.env import ISystemInfoProvider
from trac.web.chrome import INavigationContributor, ITemplateProvider, add_stylesheet
from trac.web.main import IRequestHandler
from trac.util import escape, Markup
from trac.versioncontrol.api import RepositoryManager

import gzip
import StringIO

from interfaces import IGraphicalTimelineRepository
from hgplot import createSVG, buildInfo, getTableInfo, getWidth, getHeight

class GraphicalTimeline(Component):
   """ Adds a graphical timeline page for the supported (Mercurial only at the moment) repositories """

   #supported_repositories = ExtensionPoint(IGraphicalTimelineRepository)

   implements(INavigationContributor, IRequestHandler, ITemplateProvider)

   #def __init__(self):
   #   self.supported_repositories = None

   # INavigationContributor methods
   def get_active_navigation_item(self, req):
      return 'gtimeline'

   def get_navigation_items(self, req):
      yield 'mainnav', 'gtimeline', Markup('<a href="%s">GTimeline</a>' % (self.env.href.gtimeline()))

   # IRequestHandler methods
   def match_request(self, req):
       return req.path_info == '/gtimeline' or req.path_info == '/gtimeline/timeline.svg'
   def process_request(self, req):
      supported_repos = []
      repositories = RepositoryManager(self.env).get_all_repositories()

      # Find selected repository and the supported repositories
      selected_repo = None
      for repo in repositories.values():
         if repo['type'] == 'hg':
            supported_repos.append(repo['name'])
            if repo['name'] == req.args.get('repo') or selected_repo is None:
               selected_repo = RepositoryManager(self.env).get_repository(repo['name'])
      if selected_repo is None:
         return 'notavailable.html', {}, None

      # Get branch information
      branches = selected_repo.repo.branchtags().keys()
      selected_branch = req.args.get('branch')
      if selected_branch == None or selected_branch not in branches:
         selected_branch = 'default'

      # Send response
      changes, dposx, dposy, branchColors = buildInfo(selected_repo, selected_branch)
      if req.path_info == '/gtimeline':
         data = {'svg_width' : getWidth(dposx),
                 'svg_height' : getHeight(dposy),
                 'branches' : sorted(branches), 'selected_branch' : selected_branch,
                 'repos' : supported_repos, 'selected_repo' : selected_repo.reponame,
                 'branchColors' : branchColors,
                 'tableInfo': getTableInfo(changes) }
         add_stylesheet(req, 'gtimeline/gtimeline.css')
         return 'gtimeline.html', data, None
      else:
        image = createSVG(changes, dposx, dposy, branchColors)
        self.sendTimelineImage(req, image)

    # ITemplateProvider methods
   def get_templates_dirs(self):
      from pkg_resources import resource_filename
      return [resource_filename(__name__, 'templates')]

   def get_htdocs_dirs(self):
      from pkg_resources import resource_filename
      return [('gtimeline', resource_filename(__name__, 'htdocs'))]

   # Additional helper methods
   def sendTimelineImage(self, req, image):
      req.send_response(200)
      req.send_header('Content-Type', 'image/svg+xml')
      if self.acceptsGzip(req):
         req.send_header('Content-Encoding', 'gzip')
         image = self.compressBuf(image)
      req.send_header('Content-Length', len(image))
      req.end_headers()
      req.write(image)

   def compressBuf(self, buf):
      zbuf = StringIO.StringIO()
      zfile = gzip.GzipFile(mode='wb', fileobj=zbuf, compresslevel=6)
      zfile.write(buf)
      zfile.close()
      return zbuf.getvalue()

   def acceptsGzip(self, req):
      encodings = req.get_header('Accept-Encoding')
      encodings = map(lambda x: x.strip(), encodings.split(','))
      return 'gzip' in encodings
